<?php

/*
 * CopyRight  : (C)2012-2099 HaoTeam Inc.
 * Document   : TikTokService.php
 * Created on : 2023-3-24 15:18:15
 * Author     : Tiger <1192851302@qq.com>
 * Description: This is NOT a freeware, use is subject to license terms.
 *              这即使是一个免费软件,使用时也请遵守许可证条款,得到当时人书面许可.
 *              未经书面许可,不得翻版,翻版必究;版权归属 HaoTeam Inc;
 */

namespace haoteam\service;

/**
 * 
 * Class TikTokService
 * Tiger <1192851302@qq.com> 2023-3-24 15:18:15
 */
class TikTokService {

    protected $config = [];

    /**
     * 快速实例化模型
     * @author Tiger <1192851302@qq.com>
     * @param bool $singleton 是否单例
     * @return static
     */
    public static function instance($singleton = true) {
        $name = static::class;
        if (isset($GLOBALS['model'][$name]) and is_object($GLOBALS['model'][$name]) and $singleton) {
            $that = $GLOBALS['model'][$name];
        } else {
            $GLOBALS['model'][$name] = new static();
            $that = $GLOBALS['model'][$name];
        }
        $that->config = config('third.tiktok');
        return $that;
    }

    /**
     * 登录
     * @author Tiger <1192851302@qq.com>
     * @param type $code
     * @return string appid
     * @return strimg unionid
     */
    public function session($code) {
        return $this->request('api/apps/v2/jscode2session', [
                    'appid' => $this->config['appid'],
                    'secret' => $this->config['secret'],
                    'code' => $code
        ]);
    }

    /**
     * 订阅消息发送
     * @author Tiger <1192851302@qq.com>
     * @param type $open_id
     * @param type $tpl_id
     * @param type $data
     * @param type $page
     * @return type
     */
    public function subscribe_send($open_id, $tpl_id, $data, $page) {
        $access_token = $this->access_token();
        $app_id = $this->config['appid'];
        return $this->request('api/apps/subscribe_notification/developer/v1/notify', compact('access_token', 'tpl_id', 'open_id', 'data', 'page', 'app_id'));
    }

    /**
     * 获取token
     * @author Tiger <1192851302@qq.com>
     * @return type
     */
    public function access_token() {
        $access_token = \think\facade\Cache::get('tiktok_access_token');
        if (!empty($access_token)) {
            return $access_token;
        }
        $token = $this->request('api/apps/v2/token', [
            'appid' => $this->config['appid'],
            'secret' => $this->config['secret'],
            'grant_type' => 'client_credential'
        ]);
        \think\facade\Cache::set('tiktok_access_token', $token['access_token'], $token['expires_in']);
        return $token['access_token'];
    }

    /**
     * 小程序支付
     * @author Tiger <1192851302@qq.com>
     * @param type $body
     * @param type $out_order_no
     * @param type $total_amount
     * @return type
     */
    public function bridgeConfig($body, $out_order_no, $total_amount) {
        $subject = $body;
        $valid_time = 86400;
        $notify_url = request()->domain() . '/api/tiktok/callback/payment';
        $options = compact('out_order_no', 'total_amount', 'body', 'subject', 'valid_time', 'notify_url');
        $sign = $this->sign($options);
        return $this->request('api/apps/ecpay/v1/create_order', array_merge(['sign' => $sign,
                    'app_id' => $this->config['appid']], $options));
    }

    /**
     * 异步回调
     * @author Tiger <1192851302@qq.com>
     * @param type $timestamp
     * @param type $nonce
     * @param type $msg
     * @param type $msg_signature
     * @return boolean
     */
    public function notify($timestamp, $nonce, $msg, $msg_signature) {
        if ($this->verify_sign($timestamp, $nonce, $msg, $msg_signature) == false) {
            throw new \think\Exception('签名错误');
        }
        return json_decode($msg, true);
    }

    /**
     * 支付结果查询
     * @author Tiger <1192851302@qq.com>
     * @param type $out_order_no
     * @return boolean
     */
    public function order_query($out_order_no) {
        $options = compact('out_order_no');
        $sign = $this->sign($options);
        return $this->request('api/apps/ecpay/v1/query_order', array_merge(['sign' => $sign,
                    'app_id' => $this->config['appid']], $options));
    }

    /**
     * 请求签名
     * @author Tiger <1192851302@qq.com>
     * @param array $options
     * @return type
     */
    public function sign($options) {
        $options['salt'] = $this->config['pay_salt'];
        $rList = array_values($options);
        sort($rList, SORT_STRING);
        return md5(implode('&', $rList));
    }

    /**
     * 验证签名
     * @author Tiger <1192851302@qq.com>
     * @param array $options
     * @return type
     */
    public function verify_sign($timestamp, $nonce, $msg, $msg_signature) {
        $token = $this->config['pay_token'];
        $rList = [$timestamp, $nonce, $msg, $token];
        sort($rList, SORT_STRING);
        $sing = sha1(implode('', $rList));
        if ($msg_signature != $sing) {
            return false;
        }
        return true;
    }

    /**
     * 请求
     * @author Tiger <1192851302@qq.com>
     * @param type $path
     * @param type $options
     * @param type $method
     * @return type
     * @throws \think\Exception
     */
    public function request($path, $options, $method = 'json') {
        $ret = HttpService::instance()->{$method}($this->config['api'] . $path, $options);
        if ($ret['err_no'] == 0) {
            return $ret['data'] ?? $ret;
        }
        throw new \think\Exception($ret['err_no'] . $ret['err_tips']);
    }
}
